Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add module: Linux Priv Esc (OverlayFS copying bug) CVE-2023-0386 #19441

Open
wants to merge 26 commits into
base: master
Choose a base branch
from

Conversation

Takahiro-Yoko
Copy link
Contributor

@Takahiro-Yoko Takahiro-Yoko commented Sep 5, 2024

close #18766

Vulnerable Application

This exploit targets the Linux kernel bug in OverlayFS.

A flaw was found in the Linux kernel, where unauthorized access to the execution of the setuid file with capabilities
was found in the Linux kernel’s OverlayFS subsystem in how a user copies a capable file from a nosuid mount into another mount.
This uid mapping bug allows a local user to escalate their privileges on the system.

The vulnerability affects:

* Linux kernel from (including) 5.11 up to (excluding) 5.15.91 and from (including) 5.16 Up to (excluding) 6.1.9

This module was successfully tested on:

* Ubuntu kernel version 5.13.0-1021-oem on x64/amd64
* Ubuntu kernel version 6.0.0-060000-generic on x64/amd64
* Ubuntu kernel version 6.0.19-060019-generic on x64/amd64
* Ubuntu kernel version 6.1.0-060100-generic on x64/amd64

Install

  1. Install Ubuntu version 22.04 LTS
  2. (Optional) Change kernel version
sudo apt update
sudo apt install -y linux-image-5.13.0-1021-oem linux-headers-5.13.0-1021-oem
reboot
  1. Install the required libraries
sudo apt update
sudo apt install -y gcc cmake fuse libfuse-dev libcap-dev

Verification Steps

  1. Make an Ubuntu
  2. Create a meterpreter or shell payload and upload it to the Ubuntu target
  3. Set up a handler for the payload
  4. Launch the payload as a regular user on the Ubuntu target and connect the handler
  5. Do: use exploit/linux/local/cve_2023_0386_overlayfs_priv_esc
  6. Do: run session=<session> lhost=<lhost>
  7. You should get a root

@bwatters-r7 bwatters-r7 self-assigned this Sep 5, 2024
if live_compile? && command_exists?('xxd')
vprint_status('Live compiling exploit on system...')
upload_and_compile("#{exploit_dir}/shell", exploit_source('CVE-2023-0386', 'getshell.c'))
cmd_exec("cd #{exploit_dir} && xxd -i shell > shell.xxd")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Meterepreter sessions after the cd command is executed the working directory will revert to the original directory, whereas in a shell session there will be a state change and the subsequent commands will be executed from the exploit_dir.

To better support Meterpreter sessions could you just pass in the relative directory to all commands instead running the cd?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your comment!

I intend to use cd command just for xxd command.

When using xxd command, we need -n option to set the variable name used in C include output (-i). Seems like older xxd command does not have -n option.
xxd

Without -n option and pass relative path (full path in this case, though) to xxd, variable name becomes something below (maybe / and . convert to _?).
xxdwithoutn

Handling this could cause some trouble, if not done correctly, so temporary change directory and run xxd command to specify file name without relative path. Is it acceptable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I've updated a lot, and no longer need cd command. cd97b08
Thank you!

register_file_for_cleanup(payload_path)

# Launch exploit
timeout = 30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this maybe be user configurable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! See. dc81711

Copy link
Contributor

@bwatters-r7 bwatters-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the module! You may want to check out the overlayfs module I wrote a few years ago, as a lot of the ruby code will be the same, and I think it might be worthwhile to take the same approach for launching the payload directly from within the exploit code: https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/local/cve_2021_3493_overlayfs.rb

return -1;
}

system("/bin/bash");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we instead call the binary payload directly here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!
I've tested directly calling payload using cd97b08 and 692531b (latter needs to set setuid and setgid in C code).
Seems like directly calling payload takes some time (about 1 min) to really open Meterpreter session after Meterpreter session opened message.

This one (not directly calling payload) is much faster (about a few sec). 8366252 (needs to set setuid and setgid in C code).

cmd_exec("echo '#{payload_path} & exit' | #{exploit_dir}/cve-2023-0386", nil, timeout)
end

def get_exploit(exploit_dir)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should move this to the metasploit-framework/data/external/source directory in a separate file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I've moved C code. cd97b08

#include "shell.xxd"
#define DIR_BASE "#{exploit_dir}"
Copy link
Contributor

@bwatters-r7 bwatters-r7 Sep 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EDIT- I now understand why this all looks familiar; I wrote a module for a different overlyfs exploit. I passed the exploit dir and the payload in as a parameter. You cans ee my source here: https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/local/cve_2021_3493_overlayfs.rb

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I've changed to pass the exploit directory and the payload in as a parameter. cd97b08

upload_and_compile("#{exploit_dir}/shell", exploit_source('CVE-2023-0386', 'getshell.c'))
cmd_exec("cd #{exploit_dir} && xxd -i shell > shell.xxd")
write_file("#{exploit_dir}/cve-2023-0386.c", strip_comments(get_exploit("#{exploit_dir}/.#{rand_text_alphanumeric(5..10)}")))
cmd_exec("gcc -o #{exploit_dir}/cve-2023-0386 #{exploit_dir}/cve-2023-0386.c -D_FILE_OFFSET_BITS=64 -static -lfuse -ldl -pthread")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you're using upload_and_compile above, but manually using gcc here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I misunderstood upload_and_compile's second argument is a file path. cd97b08



int main(int argc, char const *argv[]) {
if (setuid(0) < 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're using setuid and setgid here, but also in the payload?
Since the set commands are supported in the binary payloads, I don't think this is needed unless we're supporting ARCH_CMD payloads, and I don't see you using them here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EDIT- I don't think you need this; I think we can directly call the binary payload from within the exploit code itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!
cd97b08 does not need setuid and setgid.
Seems like 692531b and 8366252 need setuid and setgid, despite setting in the payload.

cmd_exec("chmod +x #{exploit_dir}/cve-2023-0386")
else
vprint_status('Dropping pre-compiled exploit on system...')
upload_and_chmodx("#{exploit_dir}/cve-2023-0386", exploit_data('CVE-2023-0386', 'cve-2023-0386'))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work if we need to change the exploit_dir value?

Copy link
Contributor Author

@Takahiro-Yoko Takahiro-Yoko Sep 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I've added directory exist check and cleanup. 920ef70 1cc562c Correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should use exploit_path? 9e832eb

end

# Upload exploit executable
exploit_dir = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why create a directory for the exploit, instead of simply putting it into #{base_dir}?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While not strictly necessary, this code pattern was introduced in local exploit modules to keep all artifacts (such as temp files from compiling on-system) within one directory which can be deleted upon completion.

https://github.com/rapid7/metasploit-framework/pull/19441/files#diff-582239976447427dfe518f2db829db0f32f85069b220a831ef7c408b06957d34R153

Given this module performs a few rm -rf calls, I'd certainly feel safer keeping exploitation contained.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

I'd certainly feel safer keeping exploitation contained.

I agree.

@Takahiro-Yoko
Copy link
Contributor Author

Thank you for reviewing!
Now I've confirmed this module is successfully working on:

* Ubuntu kernel version 5.13.0-1021-oem on x64/amd64
* Ubuntu kernel version 6.0.0-060000-generic on x64/amd64
* Ubuntu kernel version 6.0.19-060019-generic on x64/amd64
* Ubuntu kernel version 6.1.0-060100-generic on x64/amd64

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Linux Priv Esc (OverlayFS copying bug) CVE-2023-0386
5 participants